package jmine.tec.test.testcase;

import java.util.Collection;

import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.apache.log4j.Logger;
import org.springframework.transaction.TransactionStatus;

import bancosys.tec.persist.authorization.AuthorizationContext;
import bancosys.tec.persist.bussobj.AuthPersistableBusinessObject;
import bancosys.tec.persist.dao.BeanNotFoundException;

/**
 * Classe base utilizada para testar BOs fracos (weak object). <br>
 * Esses BOs são salvos a partir de um bo forte (strong object), e tem uma associação bidirecional. <br>
 * A associação bidirecional no lado cliente, tipicamente, não salva/altera a FK para o objeto forte, pois esta associação é gerenciada a
 * partir do objeto forte. <br>
 * Esse teste salva o objeto fraco a partir do forte, dessa forma, reimplementa os testSaves para criar um objeto forte, e salvar o fraco a
 * partir dele.
 * 
 * @created Jun 14, 2006
 * @author Frank Cara
 * @author galmeida (Oct 15, 2008)
 * @param <W> Weak class.
 * @param <S> Strong class.
 */
public abstract class WeakBOBaseTestCase<W extends AuthPersistableBusinessObject, S extends AuthPersistableBusinessObject> extends
        AuthBOBaseTestCase<W> {
    private static final Logger LOG = Logger.getLogger(WeakBOBaseTestCase.class);

    /**
     * Construtor.
     */
    public WeakBOBaseTestCase() {
        super();
    }

    /**
     * Construtor.
     * 
     * @param name nome do teste
     */
    public WeakBOBaseTestCase(String name) {
        super(name);
    }

    /**
     * Devolve o pai da relação master detail.
     * 
     * @return o pai da relação master detail.
     * @throws BeanNotFoundException quando o bean nao pode ser recuperado da base
     */
    protected abstract S getStrongObjectInstance() throws BeanNotFoundException;

    /**
     * Dado um pai remove os seus filhos, do próprio pai e da base.
     * 
     * @param strongObject pai.
     */
    protected abstract void cleanStrongObjectInstance(S strongObject);

    /**
     * implementa a inserção do bo a partir do seu pai
     * 
     * @param bo bo
     * @param strongObject pai
     */
    protected abstract void insertBO(AuthPersistableBusinessObject bo, S strongObject);

    /**
     * Não executa teste nenhum.
     */
    @Override
    public void testSaveAndReject() {
        LOG.trace("testSaveAndReject()");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void testSaveAndAuthorize() throws Exception {
        LOG.trace("testSaveAndAuthorize()");

        S strong;

        TransactionStatus status = this.getHelper().getTransactionStatus();
        try {
            strong = this.getStrongObjectInstance();
        } finally {
            this.getHelper().commit(status);
        }

        status = this.getHelper().getTransactionStatus();
        try {
            this.cleanStrongObjectInstance(strong);
        } finally {
            this.getHelper().commit(status);
        }

        status = this.getHelper().getTransactionStatus();
        W bo;
        try {
            this.findAllData();
            bo = this.getNewBOInstance();

            this.fillData(0, bo);

            this.getHelper().getSessionFactory().getCurrentSession().load(strong, strong.getId());
            this.insertBO(bo, strong);
            strong.getAuthorizer().save();
        } finally {
            this.getHelper().commit(status);
        }

        status = this.getHelper().getTransactionStatus();
        try {
            this.getHelper().getSessionFactory().getCurrentSession().refresh(strong);
            strong.getAuthorizer().authorize();
            this.getHelper().getSessionFactory().getCurrentSession().flush();
        } finally {
            this.getHelper().commit(status);
        }

        Collection<W> collection;

        // deve estar na quente
        status = this.getHelper().getTransactionStatus();
        try {
            collection = this.findAllData();
            assertEquals(1, collection.size());
            bo = collection.iterator().next();
            this.compareData(0, bo);
            this.comparaIdNosTestes(bo);
        } finally {
            this.getHelper().commit(status);
        }

        // nao deve estar na fria.
        status = this.getHelper().getTransactionStatus(AuthorizationContext.cold);
        try {
            collection = this.findAllData();
            assertEquals(0, collection.size());
        } finally {
            this.getHelper().commit(status);
        }
    }

    /**
     * Devolve a suite padrão.
     * 
     * @param clazz classe do testcase
     * @return suite de testes
     */
    public static TestSuite getDefaultSuite(Class<? extends TestCase> clazz) {
        return getSuite(clazz, new String[]{ "testSaveAndReject", "testSaveAndAuthorize", "testUpdateAndReject", "testUpdateAndAuthorize",
                "testRemoveAndReject", "testRemoveAndAuthorize", "testDAOQuerySyntax" });
    }

}
